package com.lkl.spring.context;

import com.lkl.spring.annotation.*;
import com.lkl.spring.service.UserService;

import javax.servlet.ServletContext;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

public class LklClassPathApplicationContext {

    private Map<String, Object> ioc = new HashMap<String, Object>();
    private Map<String, Object> handlerMap = new HashMap<String, Object>();
    /**
     * 加载配置文件
     * @return
     */
    public Properties readProperties () {
        InputStream inputStream = LklClassPathApplicationContext.class.getClassLoader()
                .getResourceAsStream("resources/application.properties");
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return properties;
    }


    public Properties readServlerProperties (ServletContext servletContext, String path) throws FileNotFoundException, UnsupportedEncodingException {
        InputStreamReader inputStream = new InputStreamReader(new FileInputStream(servletContext.getRealPath(path)), "UTF-8");
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return properties;
    }

    public List<String> findClass (Properties properties) throws UnsupportedEncodingException {
        String classPath = properties.get("scanpacage").toString();

        //获取类路径
        URL url = this.getClass().getClassLoader().getResource("");
        String contextPath = url.getPath();

        contextPath = URLDecoder.decode(contextPath, "UTF-8");


        String packageName = classPath.replaceAll("\\.","/");//去 掉.类名

        //装载类的全路径名
        List<String> list = new ArrayList<String>();

        File file = new File(contextPath + packageName);

        //递归查找该路径下所有的类
        scanpackage(file, list, packageName);

        return list;
    }

    /**
     * 根据注解判断是否需要实例化
     * @param pacageClass
     */
    public void newInstance (List<String> pacageClass) throws Exception {
        //实例化类
        for (String cla : pacageClass) {
            try {
                Class<?> clazz = Class.forName(cla);
                Annotation[] annotations = clazz.getAnnotations();
                Object instance;
                for (Annotation annotation : annotations) {
                    if (annotation instanceof LklService) {
                        instance = clazz.newInstance();
                        ioc.put(((LklService) annotation).value(), instance);
                    }

                    if (annotation instanceof LklRepository) {
                        instance = clazz.newInstance();
                        ioc.put(((LklRepository) annotation).value(), instance);
                    }

                    if (annotation instanceof LklController) {
                        instance = clazz.newInstance();
                        ioc.put(((LklController) annotation).value(), instance);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //依赖注入，变量
        Set<String> stringSet = this.ioc.keySet();
        for (String key : stringSet) {
            Object instance = this.ioc.get(key);
            Class<?> clazz = instance.getClass();
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                Annotation[] annotations = field.getAnnotations();
                for (Annotation annotation : annotations) {

                    if (annotation instanceof LklAutowird) {
                        String fieldName = field.getName();
                        field.setAccessible(true);
                        field.set(instance, this.ioc.get(fieldName));
                    }
                }
            }

            //依赖注入handler
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                Annotation[] annotations = method.getDeclaredAnnotations();
                for (Annotation annotation : annotations) {
                    if (annotation instanceof LklRequestMapping) {
                        String actionUrl = ((LklRequestMapping) annotation).value();
                        if (this.handlerMap.get(actionUrl) != null) {
                            throw new Exception(actionUrl + ": 已经存在映射对象" + this.handlerMap.get(actionUrl));
                        }
                        //LklController lklController = clazz.getAnnotation(LklController.class);
                        this.handlerMap.put(actionUrl, method);
                    }


                }
            }
        }
    }

    /**
     * 根据注入别名查找
     * @param beanId
     * @return
     */
    public Object getBean (String beanId) {
        return this.ioc.get(beanId);
    }


    /**
     * 扫描指定包下的所有的类的全路径名
     * @param file
     * @param list
     * @param packageName
     */
    public void scanpackage(File file, List<String> list, String packageName) {
        File[] fileList = file.listFiles();
        for (File file1 : fileList) {
            if (file1.isDirectory()) {
             scanpackage(file1, list, packageName + "/" + file1.getName());
            }else {
                String tempClass = packageName + "/" + file1.getName();
                tempClass = tempClass.replaceAll("/", "\\.");
                tempClass = tempClass.substring(0, tempClass.indexOf(".class"));
                list.add(tempClass);
            }
        }
    }

    public Map<String, Object> getIoc() {
        return ioc;
    }

    public void setIoc(Map<String, Object> ioc) {
        this.ioc = ioc;
    }

    public Map<String, Object> getHandlerMap() {
        return handlerMap;
    }

    public void setHandlerMap(Map<String, Object> handlerMap) {
        this.handlerMap = handlerMap;
    }

    public static void main(String[] args) throws Exception {
        LklClassPathApplicationContext context = new LklClassPathApplicationContext();
        Properties properties = context.readProperties();
        List<String> list = context.findClass(properties);
        context.newInstance(list);
        UserService userService = (UserService) context.getBean("userService");
        userService.addUser();
    }

}
